/*
	The Raja Toolkit.
	Copyright (C) 2011 Raja-Toolkit Foundation

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 3.0 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/


#include "matrix.hpp"

/// @addtogroup raja
/// @{
namespace raja
{
/// @addtogroup math
/// @{
namespace math
{

///////////////////////////////////////////////////////////////////////
/// mat2
///////////////////////////////////////////////////////////////////////

/// constructor
template<typename T>
tmat2<T>::tmat2()
{
	col[0] = vec2_t(T(1), T(0));
	col[1] = vec2_t(T(0), T(1));
}

template<typename T>
tmat2<T>::tmat2(T m00, T m10, T m01, T m11)
{
	col[0] = vec2_t(m00, m10);
	col[1] = vec2_t(m01, m11);
}

template<typename T>
tmat2<T>::tmat2(const vec2_t &c0, const vec2_t &c1)
{
	col[0] = c0;
	col[1] = c1;
}

template<typename T>
tmat2<T>::tmat2(const tmat2<T> &m)
{
	col[0] = m.col[0];
	col[1] = m.col[1];
}

/// addition
template<typename T>
tmat2<T>& tmat2<T>::operator +=(const tmat2<T> &m)
{
	col[0] += m.col[0];
	col[1] += m.col[1];
	return (*this);
}

/// substraction
template<typename T>
tmat2<T>& tmat2<T>::operator -=(const tmat2<T> &m)
{
	col[0] -= m.col[0];
	col[1] -= m.col[1];
	return (*this);
}

/// multiplication
template<typename T>
tmat2<T>& tmat2<T>::operator *=(const tmat2<T> &m)
{
	col[0] *= m.col[0];
	col[1] *= m.col[1];
	return (*this);
}

/// division
template<typename T>
tmat2<T>& tmat2<T>::operator /=(const tmat2<T> &m)
{
	col[0] /= m.col[0];
	col[1] /= m.col[1];
	return (*this);
}

/// prefix increment
template<typename T>
tmat2<T>& tmat2<T>::operator++()
{
	++col[0];
	++col[1];
	return (*this);
}

/// prefix decrement
template<typename T>
tmat2<T>& tmat2<T>::operator--()
{
	--col[0];
	--col[1];
	return (*this);
}

/// postfix increment
template<typename T>
tmat2<T> tmat2<T>::operator++(int)
{
	tmat2<T> res(*this);
	++col[0];
	++col[1];
	return res;
}

/// postfix decrement
template<typename T>
tmat2<T> tmat2<T>::operator--(int)
{
	tmat2<T> res(*this);
	--col[0];
	--col[1];
	return res;
}

/// assignment
template<typename T>
tmat2<T>& tmat2<T>::operator =(const tmat2<T> &m)
{
	col[0] = m.col[0];
	col[1] = m.col[1];
	return (*this);
}

///////////////////////////////////////////////////////////////////////
template struct tmat2<real32>;
template struct tmat2<real64>;
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
/// mat3
///////////////////////////////////////////////////////////////////////
template<typename T>
tmat3<T>::tmat3()
{
	col[0] = vec3_t(T(1), T(0), T(0));
	col[1] = vec3_t(T(0), T(1), T(0));
	col[2] = vec3_t(T(0), T(0), T(1));
}

template<typename T>
tmat3<T>::tmat3(T m00, T m10, T m20,
				T m01, T m11, T m21,
				T m02, T m12, T m22)
{
	col[0] = vec3_t(m00, m10, m20);
	col[1] = vec3_t(m01, m11, m21);
	col[2] = vec3_t(m02, m12, m22);
}

template<typename T>
tmat3<T>::tmat3(const vec3_t &c0, const vec3_t &c1, const vec3_t &c2)
{
	col[0] = c0;
	col[1] = c1;
	col[2] = c2;
}

template<typename T>
tmat3<T>::tmat3(const tmat3<T> &m)
{
	col[0] = m.col[0];
	col[1] = m.col[1];
	col[2] = m.col[2];
}

/// addition
template<typename T>
tmat3<T>& tmat3<T>::operator +=(const tmat3<T> &m)
{
	col[0] += m.col[0];
	col[1] += m.col[1];
	col[2] += m.col[2];
	return (*this);
}

/// substraction
template<typename T>
tmat3<T>& tmat3<T>::operator -=(const tmat3<T> &m)
{
	col[0] -= m.col[0];
	col[1] -= m.col[1];
	col[2] -= m.col[2];
	return (*this);
}

/// multiplication
template<typename T>
tmat3<T>& tmat3<T>::operator *=(const tmat3<T> &m)
{
	col[0] *= m.col[0];
	col[1] *= m.col[1];
	col[2] *= m.col[2];
	return (*this);
}

/// division
template<typename T>
tmat3<T>& tmat3<T>::operator /=(const tmat3<T> &m)
{
	col[0] /= m.col[0];
	col[1] /= m.col[1];
	col[2] /= m.col[2];
	return (*this);
}

/// prefix increment
template<typename T>
tmat3<T>& tmat3<T>::operator++()
{
	++col[0];
	++col[1];
	++col[2];
	return (*this);
}

/// prefix decrement
template<typename T>
tmat3<T>& tmat3<T>::operator--()
{
	--col[0];
	--col[1];
	--col[2];
	return (*this);
}

/// postfix increment
template<typename T>
tmat3<T> tmat3<T>::operator++(int)
{
	tmat3<T> res(*this);
	++col[0];
	++col[1];
	++col[2];
	return res;
}

/// postfix decrement
template<typename T>
tmat3<T> tmat3<T>::operator--(int)
{
	tmat3<T> res(*this);
	--col[0];
	--col[1];
	--col[2];
	return res;
}

/// assignment
template<typename T>
tmat3<T>& tmat3<T>::operator =(const tmat3<T> &m)
{
	col[0] = m.col[0];
	col[1] = m.col[1];
	col[2] = m.col[2];
	return (*this);
}

///////////////////////////////////////////////////////////////////////
template struct tmat3<real32>;
template struct tmat3<real64>;
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
/// mat4
///////////////////////////////////////////////////////////////////////

template<typename T>
tmat4<T>::tmat4()
{
	col[0] = vec4_t(T(1), T(0), T(0), T(0));
	col[1] = vec4_t(T(0), T(1), T(0), T(0));
	col[2] = vec4_t(T(0), T(0), T(1), T(0));
	col[3] = vec4_t(T(0), T(0), T(0), T(1));
}

template<typename T>
tmat4<T>::tmat4(T m00, T m10, T m20, T m30,
				T m01, T m11, T m21, T m31,
				T m02, T m12, T m22, T m32,
				T m03, T m13, T m23, T m33)
{
	col[0] = vec4_t(m00, m10, m20, m30);
	col[1] = vec4_t(m01, m11, m21, m31);
	col[2] = vec4_t(m02, m12, m22, m32);
	col[3] = vec4_t(m03, m13, m23, m33);
}

template<typename T>
tmat4<T>::tmat4(const vec4_t &c0, const vec4_t &c1, const vec4_t &c2, const vec4_t &c3)
{
	col[0] = c0;
	col[1] = c1;
	col[2] = c2;
	col[3] = c3;
}

template<typename T>
tmat4<T>::tmat4(const tmat4<T> &m)
{
	col[0] = m.col[0];
	col[1] = m.col[1];
	col[2] = m.col[2];
	col[3] = m.col[3];
}

/// addition
template<typename T>
tmat4<T>& tmat4<T>::operator +=(const tmat4<T> &m)
{
	col[0] += m.col[0];
	col[1] += m.col[1];
	col[2] += m.col[2];
	col[3] += m.col[3];
	return (*this);
}

/// substraction
template<typename T>
tmat4<T>& tmat4<T>::operator -=(const tmat4<T> &m)
{
	col[0] -= m.col[0];
	col[1] -= m.col[1];
	col[2] -= m.col[2];
	col[3] -= m.col[3];
	return (*this);
}

/// multiplication
template<typename T>
tmat4<T>& tmat4<T>::operator *=(const tmat4<T> &m)
{
	col[0] *= m.col[0];
	col[1] *= m.col[1];
	col[2] *= m.col[2];
	col[3] *= m.col[3];
	return (*this);
}

/// division
template<typename T>
tmat4<T>& tmat4<T>::operator /=(const tmat4<T> &m)
{
	col[0] /= m.col[0];
	col[1] /= m.col[1];
	col[2] /= m.col[2];
	col[3] /= m.col[3];
	return (*this);
}

/// prefix increment
template<typename T>
tmat4<T>& tmat4<T>::operator++()
{
	++col[0];
	++col[1];
	++col[2];
	++col[3];
	return (*this);
}

/// prefix decrement
template<typename T>
tmat4<T>& tmat4<T>::operator--()
{
	--col[0];
	--col[1];
	--col[2];
	--col[3];
	return (*this);
}

/// postfix increment
template<typename T>
tmat4<T> tmat4<T>::operator++(int)
{
	tmat4<T> res(*this);
	++col[0];
	++col[1];
	++col[2];
	++col[3];
	return res;
}

/// postfix decrement
template<typename T>
tmat4<T> tmat4<T>::operator--(int)
{
	tmat4<T> res(*this);
	--col[0];
	--col[1];
	--col[2];
	--col[3];
	return res;
}

/// assignment
template<typename T>
tmat4<T>& tmat4<T>::operator =(const tmat4<T> &m)
{
	col[0] = m.col[0];
	col[1] = m.col[1];
	col[2] = m.col[2];
	col[3] = m.col[3];
	return (*this);
}

///////////////////////////////////////////////////////////////////////
template struct tmat4<real32>;
template struct tmat4<real64>;
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
/// operators
///////////////////////////////////////////////////////////////////////

/// comparison
template<typename T>
bool operator ==(const tmat2<T> &m0, const tmat2<T> &m1)
{
	return (m0.col[0] == m1.col[0] && m0.col[1] == m1.col[1]);
}

template<typename T>
bool operator ==(const tmat3<T> &m0, const tmat3<T> &m1)
{
	return (m0.col[0] == m1.col[0] && m0.col[1] == m1.col[1]
			&& m0.col[2] == m1.col[2]);
}

template<typename T>
bool operator ==(const tmat4<T> &m0, const tmat4<T> &m1)
{
	return (m0.col[0] == m1.col[0] && m0.col[1] == m1.col[1]
			&& m0.col[2] == m1.col[2] && m0.col[3] == m1.col[3]);
}

///////////////////////////////////////////////////////////////////////////////
template bool operator == <real32> (const tmat2<real32> &m0, const tmat2<real32> &m1);
template bool operator == <real64> (const tmat2<real64> &m0, const tmat2<real64> &m1);

template bool operator == <real32> (const tmat3<real32> &m0, const tmat3<real32> &m1);
template bool operator == <real64> (const tmat3<real64> &m0, const tmat3<real64> &m1);

template bool operator == <real32> (const tmat4<real32> &m0, const tmat4<real32> &m1);
template bool operator == <real64> (const tmat4<real64> &m0, const tmat4<real64> &m1);
///////////////////////////////////////////////////////////////////////////////

/// addition
template<typename T>
tmat2<T> operator + (const tmat2<T> &m, T s)
{
	return tmat2<T>(m.col[0] + s, m.col[1] + s);
}

template<typename T>
tmat3<T> operator + (const tmat3<T> &m, T s)
{
	return tmat3<T>(m.col[0] + s, m.col[1] + s, m.col[2] + s);
}

template<typename T>
tmat4<T> operator + (const tmat4<T> &m, T s)
{
	return tmat4<T>(m.col[0] + s, m.col[1] + s, m.col[2] + s, m.col[3] + s);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator + <real32> (const tmat2<real32> &m, real32 s);
template tmat2<real64> operator + <real64> (const tmat2<real64> &m, real64 s);

template tmat3<real32> operator + <real32> (const tmat3<real32> &m, real32 s);
template tmat3<real64> operator + <real64> (const tmat3<real64> &m, real64 s);

template tmat4<real32> operator + <real32> (const tmat4<real32> &m, real32 s);
template tmat4<real64> operator + <real64> (const tmat4<real64> &m, real64 s);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat2<T> operator + (T s, const tmat2<T> &m)
{
	return tmat2<T>(m.col[0] + s, m.col[1] + s);
}

template<typename T>
tmat3<T> operator + (T s, const tmat3<T> &m)
{
	return tmat3<T>(m.col[0] + s, m.col[1] + s, m.col[2] + s);
}

template<typename T>
tmat4<T> operator + (T s, const tmat4<T> &m)
{
	return tmat4<T>(m.col[0] + s, m.col[1] + s, m.col[2] + s, m.col[3] + s);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator + <real32>(real32 s, const tmat2<real32> &m);
template tmat2<real64> operator + <real64>(real64 s, const tmat2<real64> &m);

template tmat3<real32> operator + <real32>(real32 s, const tmat3<real32> &m);
template tmat3<real64> operator + <real64>(real64 s, const tmat3<real64> &m);

template tmat4<real32> operator + <real32>(real32 s, const tmat4<real32> &m);
template tmat4<real64> operator + <real64>(real64 s, const tmat4<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template <typename T>
tmat2<T> operator + (const tmat2<T> &m0, const tmat2<T> &m1)
{
	return tmat2<T>(m0.col[0] + m1.col[0], m0.col[1] + m1.col[1]);
}

template <typename T>
tmat3<T> operator + (const tmat3<T> &m0, const tmat3<T> &m1)
{
	return tmat3<T>(m0.col[0] + m1.col[0],
				m0.col[1] + m1.col[1],
				m0.col[2] + m1.col[2]);
}

template <typename T>
tmat4<T> operator + (const tmat4<T> &m0, const tmat4<T> &m1)
{
	return tmat4<T>(m0.col[0] + m1.col[0],
				m0.col[1] + m1.col[1],
				m0.col[2] + m1.col[2],
				m0.col[3] + m1.col[3]);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator + <real32>(const tmat2<real32> &m0, const tmat2<real32> &m1);
template tmat2<real64> operator + <real64>(const tmat2<real64> &m0, const tmat2<real64> &m1);

template tmat3<real32> operator + <real32>(const tmat3<real32> &m0, const tmat3<real32> &m1);
template tmat3<real64> operator + <real64>(const tmat3<real64> &m0, const tmat3<real64> &m1);

template tmat4<real32> operator + <real32>(const tmat4<real32> &m0, const tmat4<real32> &m1);
template tmat4<real64> operator + <real64>(const tmat4<real64> &m0, const tmat4<real64> &m1);
///////////////////////////////////////////////////////////////////////////////

/// substraction
template<typename T>
tmat2<T> operator - (const tmat2<T> &m, T s)
{
	return tmat2<T>(m.col[0] - s, m.col[1] - s);
}

template<typename T>
tmat3<T> operator - (const tmat3<T> &m, T s)
{
	return tmat3<T>(m.col[0] - s, m.col[1] - s, m.col[2] - s);
}

template<typename T>
tmat4<T> operator - (const tmat4<T> &m, T s)
{
	return tmat4<T>(m.col[0] - s, m.col[1] - s, m.col[2] - s, m.col[3] - s);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator - <real32>(const tmat2<real32> &m, real32 s);
template tmat2<real64> operator - <real64>(const tmat2<real64> &m, real64 s);

template tmat3<real32> operator - <real32>(const tmat3<real32> &m, real32 s);
template tmat3<real64> operator - <real64>(const tmat3<real64> &m, real64 s);

template tmat4<real32> operator - <real32>(const tmat4<real32> &m, real32 s);
template tmat4<real64> operator - <real64>(const tmat4<real64> &m, real64 s);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat2<T> operator - (T s, const tmat2<T> &m)
{
	return tmat2<T>(s - m.col[0], s - m.col[1]);
}

template<typename T>
tmat3<T> operator - (T s, const tmat3<T> &m)
{
	return tmat3<T>(s - m.col[0], s - m.col[1], s - m.col[2]);
}

template<typename T>
tmat4<T> operator - (T s, const tmat4<T> &m)
{
	return tmat4<T>(s - m.col[0], s - m.col[1], s - m.col[2], s - m.col[3]);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator - (real32 s, const tmat2<real32> &m);
template tmat2<real64> operator - (real64 s, const tmat2<real64> &m);

template tmat3<real32> operator - (real32 s, const tmat3<real32> &m);
template tmat3<real64> operator - (real64 s, const tmat3<real64> &m);

template tmat4<real32> operator - (real32 s, const tmat4<real32> &m);
template tmat4<real64> operator - (real64 s, const tmat4<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat2<T> operator - (const tmat2<T> &m0, const tmat2<T> &m1)
{
	return tmat2<T>(m0.col[0] - m1.col[0], m0.col[1] - m1.col[1]);
}

template<typename T>
tmat3<T> operator - (const tmat3<T> &m0, const tmat3<T> &m1)
{
	return tmat3<T>(m0.col[0] - m1.col[0],
					m0.col[1] - m1.col[1],
					m0.col[2] - m1.col[2]);
}

template<typename T>
tmat4<T> operator - (const tmat4<T> &m0, const tmat4<T> &m1)
{
	return tmat4<T>(m0.col[0] - m1.col[0],
					m0.col[1] - m1.col[1],
					m0.col[2] - m1.col[2],
					m0.col[3] - m1.col[3]);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator - <real32>(const tmat2<real32> &m0, const tmat2<real32> &m1);
template tmat2<real64> operator - <real64>(const tmat2<real64> &m0, const tmat2<real64> &m1);

template tmat3<real32> operator - <real32>(const tmat3<real32> &m0, const tmat3<real32> &m1);
template tmat3<real64> operator - <real64>(const tmat3<real64> &m0, const tmat3<real64> &m1);

template tmat4<real32> operator - <real32>(const tmat4<real32> &m0, const tmat4<real32> &m1);
template tmat4<real64> operator - <real64>(const tmat4<real64> &m0, const tmat4<real64> &m1);
///////////////////////////////////////////////////////////////////////////////

/// division
template<typename T>
tmat2<T> operator / (const tmat2<T> &m, T s)
{
	return tmat2<T>(m.col[0] / s, m.col[1] / s);
}

template<typename T>
tmat3<T> operator / (const tmat3<T> &m, T s)
{
	return tmat3<T>(m.col[0] / s, m.col[1] / s, m.col[2] / s);
}

template<typename T>
tmat4<T> operator / (const tmat4<T> &m, T s)
{
	return tmat4<T>(m.col[0] / s, m.col[1] / s, m.col[2] / s, m.col[3] / s);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator / <real32>(const tmat2<real32> &m, real32 s);
template tmat2<real64> operator / <real64>(const tmat2<real64> &m, real64 s);

template tmat3<real32> operator / <real32>(const tmat3<real32> &m, real32 s);
template tmat3<real64> operator / <real64>(const tmat3<real64> &m, real64 s);

template tmat4<real32> operator / <real32>(const tmat4<real32> &m, real32 s);
template tmat4<real64> operator / <real64>(const tmat4<real64> &m, real64 s);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat2<T> operator / (T s, const tmat2<T> &m)
{
	return tmat2<T>(s / m.col[0], s / m.col[1]);
}

template<typename T>
tmat3<T> operator / (T s, const tmat3<T> &m)
{
	return tmat3<T>(s / m.col[0], s / m.col[1], s / m.col[2]);
}

template<typename T>
tmat4<T> operator / (T s, const tmat4<T> &m)
{
	return tmat4<T>(s / m.col[0], s / m.col[1], s / m.col[2], s / m.col[3]);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator / <real32>(real32 s, const tmat2<real32> &m);
template tmat2<real64> operator / <real64>(real64 s, const tmat2<real64> &m);

template tmat3<real32> operator / <real32>(real32 s, const tmat3<real32> &m);
template tmat3<real64> operator / <real64>(real64 s, const tmat3<real64> &m);

template tmat4<real32> operator / <real32>(real32 s, const tmat4<real32> &m);
template tmat4<real64> operator / <real64>(real64 s, const tmat4<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template <typename T>
tmat2<T> operator / (const tmat2<T> &m0, const tmat2<T> &m1)
{
	return tmat2<T>(m0.col[0] / m1.col[0], m0.col[1] / m1.col[1]);
}

template <typename T>
tmat3<T> operator / (const tmat3<T> &m0, const tmat3<T> &m1)
{
	return tmat3<T>(m0.col[0] / m1.col[0], m0.col[1] / m1.col[1], m0.col[2] / m1.col[2]);
}

template <typename T>
tmat4<T> operator / (const tmat4<T> &m0, const tmat4<T> &m1)
{
	return tmat4<T>(m0.col[0] / m1.col[0], m0.col[1] / m1.col[1],
					m0.col[2] / m1.col[2], m0.col[3] / m1.col[3]);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator / <real32>(const tmat2<real32> &m0, const tmat2<real32> &m1);
template tmat2<real64> operator / <real64>(const tmat2<real64> &m0, const tmat2<real64> &m1);

template tmat3<real32> operator / <real32>(const tmat3<real32> &m0, const tmat3<real32> &m1);
template tmat3<real64> operator / <real64>(const tmat3<real64> &m0, const tmat3<real64> &m1);

template tmat4<real32> operator / <real32>(const tmat4<real32> &m0, const tmat4<real32> &m1);
template tmat4<real64> operator / <real64>(const tmat4<real64> &m0, const tmat4<real64> &m1);
///////////////////////////////////////////////////////////////////////////////

/// multiplication
template<typename T>
tmat2<T> operator * (const tmat2<T> &m, T s)
{
	return tmat2<T>(m.col[0] * s, m.col[1] * s);
}

template<typename T>
tmat3<T> operator * (const tmat3<T> &m, T s)
{
	return tmat3<T>(m.col[0] * s, m.col[1] * s, m.col[2] * s);
}

template<typename T>
tmat4<T> operator * (const tmat4<T> &m, T s)
{
	return tmat4<T>(m.col[0] * s, m.col[1] * s, m.col[2] * s, m.col[3] * s);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator * <real32>(const tmat2<real32> &m, real32 s);
template tmat2<real64> operator * <real64>(const tmat2<real64> &m, real64 s);

template tmat3<real32> operator * <real32>(const tmat3<real32> &m, real32 s);
template tmat3<real64> operator * <real64>(const tmat3<real64> &m, real64 s);

template tmat4<real32> operator * <real32>(const tmat4<real32> &m, real32 s);
template tmat4<real64> operator * <real64>(const tmat4<real64> &m, real64 s);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat2<T> operator * (T s, const tmat2<T> &m)
{
	return tmat2<T>(s * m.col[0], s * m.col[1]);
}

template<typename T>
tmat3<T> operator * (T s, const tmat3<T> &m)
{
	return tmat3<T>(s * m.col[0], s * m.col[1], s * m.col[2]);
}

template<typename T>
tmat4<T> operator *(T s, const tmat4<T> &m)
{
	return tmat4<T>(s * m.col[0], s * m.col[1], s * m.col[2], s * m.col[3]);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator * <real32>(real32 s, const tmat2<real32> &m);
template tmat2<real64> operator * <real64>(real64 s, const tmat2<real64> &m);

template tmat3<real32> operator * <real32>(real32 s, const tmat3<real32> &m);
template tmat3<real64> operator * <real64>(real64 s, const tmat3<real64> &m);

template tmat4<real32> operator * <real32>(real32 s, const tmat4<real32> &m);
template tmat4<real64> operator * <real64>(real64 s, const tmat4<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat2<T> operator * (const tmat2<T> &a, const tmat2<T> &b)
{
	T	a00 = a.col[0].x;
	T	a10 = a.col[0].y;
	T	a01 = a.col[1].x;
	T	a11 = a.col[1].y;

	T	b00 = b.col[0].x;
	T	b10 = b.col[0].y;
	T	b01 = b.col[1].x;
	T	b11 = b.col[1].y;

	T	c00 = a00 * b00 + a01 * b10;
	T	c01 = a00 * b01 + a01 * b11;
	T	c10 = a10 * b00 + a11 * b10;
	T	c11 = a10 * b01 + a11 * b11;

	return tmat2<T>(c00, c10, c01, c11);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> operator * <real32>(const tmat2<real32> &a, const tmat2<real32> &b);
template tmat2<real64> operator * <real64>(const tmat2<real64> &a, const tmat2<real64> &b);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat3<T> operator * (const tmat3<T> &a, const tmat3<T> &b)
{
	T	a00 = a.col[0].x;
	T	a10 = a.col[0].y;
	T	a20 = a.col[0].z;

	T	a01 = a.col[1].x;
	T	a11 = a.col[1].y;
	T	a21 = a.col[1].z;

	T	a02 = a.col[2].x;
	T	a12 = a.col[2].y;
	T	a22 = a.col[2].z;

	T	b00 = b.col[0].x;
	T	b10 = b.col[0].y;
	T	b20 = b.col[0].z;

	T	b01 = b.col[1].x;
	T	b11 = b.col[1].y;
	T	b21 = b.col[1].z;

	T	b02 = b.col[2].x;
	T	b12 = b.col[2].y;
	T	b22 = b.col[2].z;

	T	c00 = a00 * b00 + a01 * b10 + a02 * b20;
	T	c01 = a00 * b01 + a01 * b11 + a02 * b21;
	T	c02 = a00 * b02 + a01 * b12 + a02 * b22;

	T	c10 = a10 * b00 + a11 * b10 + a12 * b20;
	T	c11 = a10 * b01 + a11 * b11 + a12 * b21;
	T	c12 = a10 * b02 + a11 * b12 + a12 * b22;

	T	c20 = a20 * b00 + a21 * b10 + a22 * b20;
	T	c21 = a20 * b01 + a21 * b11 + a22 * b21;
	T	c22 = a20 * b02 + a21 * b12 + a22 * b22;

	return tmat3<T>(c00, c10, c20,
					c01, c11, c21,
					c02, c12, c22);
}

///////////////////////////////////////////////////////////////////////////////
template tmat3<real32> operator * <real32>(const tmat3<real32> &a, const tmat3<real32> &b);
template tmat3<real64> operator * <real64>(const tmat3<real64> &a, const tmat3<real64> &b);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat4<T> operator * (const tmat4<T> &a, const tmat4<T> &b)
{
	T	a00 = a.col[0].x;
	T	a10 = a.col[0].y;
	T	a20 = a.col[0].z;
	T	a30 = a.col[0].w;

	T	a01 = a.col[1].x;
	T	a11 = a.col[1].y;
	T	a21 = a.col[1].z;
	T	a31 = a.col[1].w;

	T	a02 = a.col[2].x;
	T	a12 = a.col[2].y;
	T	a22 = a.col[2].z;
	T	a32 = a.col[2].w;

	T	a03 = a.col[3].x;
	T	a13 = a.col[3].y;
	T	a23 = a.col[3].z;
	T	a33 = a.col[3].w;

	T	b00 = b.col[0].x;
	T	b10 = b.col[0].y;
	T	b20 = b.col[0].z;
	T	b30 = b.col[0].w;

	T	b01 = b.col[1].x;
	T	b11 = b.col[1].y;
	T	b21 = b.col[1].z;
	T	b31 = b.col[1].w;

	T	b02 = b.col[2].x;
	T	b12 = b.col[2].y;
	T	b22 = b.col[2].z;
	T	b32 = b.col[2].w;

	T	b03 = b.col[3].x;
	T	b13 = b.col[3].y;
	T	b23 = b.col[3].z;
	T	b33 = b.col[3].w;

	T	c00 = a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30;
	T	c01 = a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31;
	T	c02 = a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32;
	T	c03 = a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33;

	T	c10 = a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30;
	T	c11 = a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31;
	T	c12 = a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32;
	T	c13 = a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33;

	T	c20 = a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30;
	T	c21 = a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31;
	T	c22 = a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32;
	T	c23 = a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33;

	T	c30 = a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30;
	T	c31 = a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31;
	T	c32 = a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32;
	T	c33 = a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33;

	return tmat4<T>(c00, c10, c20, c30,
					c01, c11, c21, c31,
					c02, c12, c22, c32,
					c03, c13, c23, c33);
}

///////////////////////////////////////////////////////////////////////////////
template tmat4<real32> operator * <real32> (const tmat4<real32> &a, const tmat4<real32> &b);
template tmat4<real64> operator * <real64> (const tmat4<real64> &a, const tmat4<real64> &b);
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
/// vector matrix operations
///////////////////////////////////////////////////////////////////////

template<typename T>
tvec2<T> operator * (const tvec2<T> &v, const tmat2<T> &m)
{
	tvec2<T> res = tvec2<T>(dot(v, m.col[0]), dot(v, m.col[1]));
	return res;
}

///////////////////////////////////////////////////////////////////////////////
template tvec2<real32> operator * <real32>(const tvec2<real32> &v, const tmat2<real32> &m);
template tvec2<real64> operator * <real64>(const tvec2<real64> &v, const tmat2<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tvec2<T> operator * (const tmat2<T> &m, const tvec2<T> &v)
{
	const tvec2<T> &m0 = m.col[0];
	const tvec2<T> &m1 = m.col[1];

	tvec2<T> res = tvec2<T>(v.x * m0.x + v.y * m1.x, v.x * m0.y + v.y * m1.y);
	return res;
}

///////////////////////////////////////////////////////////////////////////////
template tvec2<real32> operator * <real32>(const tmat2<real32> &m, const tvec2<real32> &v);
template tvec2<real64> operator * <real64>(const tmat2<real64> &m, const tvec2<real64> &v);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tvec3<T> operator * (const tvec3<T> &v, const tmat3<T> &m)
{
	tvec3<T> res = tvec3<T>(dot(v, m.col[0]), dot(v, m.col[1]),	dot(v, m.col[2]));
	return res;
}

///////////////////////////////////////////////////////////////////////////////
template tvec3<real32> operator * <real32>(const tvec3<real32> &v, const tmat3<real32> &m);
template tvec3<real64> operator * <real64>(const tvec3<real64> &v, const tmat3<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tvec3<T> operator * (const tmat3<T> &m, const tvec3<T> &v)
{
	const tvec3<T>	&m0 = m.col[0];
	const tvec3<T>	&m1 = m.col[1];
	const tvec3<T>	&m2 = m.col[2];

	tvec3<T> res	= tvec3<T>(v.x * m0.x + v.y * m1.x + v.z * m2.x,
							   v.x * m0.y + v.y * m1.y + v.z * m2.y,
							   v.x * m0.z + v.y * m1.z + v.z * m2.z);
	return res;
}

///////////////////////////////////////////////////////////////////////////////
template tvec3<real32> operator * <real32>(const tmat3<real32> &m, const tvec3<real32> &v);
template tvec3<real64> operator * <real64>(const tmat3<real64> &m, const tvec3<real64> &v);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tvec4<T> operator * (const tvec4<T> &v, const tmat4<T> &m)
{
	tvec4<T> res = tvec4<T>(dot(v, m.col[0]), dot(v, m.col[1]),
							dot(v, m.col[2]), dot(v, m.col[3]));
	return res;
}

///////////////////////////////////////////////////////////////////////////////
template tvec4<real32> operator * <real32>(const tvec4<real32> &v, const tmat4<real32> &m);
template tvec4<real64> operator * <real64>(const tvec4<real64> &v, const tmat4<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tvec4<T> operator * (const tmat4<T> &m, const tvec4<T> &v)
{
	const tvec4<T>	&m0 = m.col[0];
	const tvec4<T>	&m1 = m.col[1];
	const tvec4<T>	&m2 = m.col[2];
	const tvec4<T>	&m3 = m.col[3];

	tvec4<T> res = tvec4<T>(v.x * m0.x + v.y * m1.x + v.z * m2.x + v.w * m3.x,
							v.x * m0.y + v.y * m1.y + v.z * m2.y + v.w * m3.y,
							v.x * m0.z + v.y * m1.z + v.z * m2.z + v.w * m3.z,
							v.x * m0.w + v.y * m1.w + v.z * m2.w + v.w * m3.w);
	return res;
}

///////////////////////////////////////////////////////////////////////////////
template tvec4<real32>	operator * <real32> (const tmat4<real32> &m, const tvec4<real32> &v);
template tvec4<real64>	operator * <real64> (const tmat4<real64> &m, const tvec4<real64> &v);
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
/// transpose
///////////////////////////////////////////////////////////////////////

template<typename T>
tmat2<T> transpose(const tmat2<T> &m)
{
	T	m00 = m.col[0].x;
	T	m10 = m.col[0].y;

	T	m01 = m.col[1].x;
	T	m11 = m.col[1].y;

	return tmat2<T>(m00, m01,
					m10, m11);
}


///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> transpose<real32>(const tmat2<real32> &m);
template tmat2<real64> transpose<real64>(const tmat2<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat3<T> transpose(const tmat3<T> &m)
{
	T	m00 = m.col[0].x;
	T	m10 = m.col[0].y;
	T	m20 = m.col[0].z;

	T	m01 = m.col[1].x;
	T	m11 = m.col[1].y;
	T	m21 = m.col[1].z;

	T	m02 = m.col[2].x;
	T	m12 = m.col[2].y;
	T	m22 = m.col[2].z;

	return tmat3<T>(m00, m01, m02,
					m10, m11, m12,
					m20, m21, m22);
}

///////////////////////////////////////////////////////////////////////////////
template tmat3<real32> transpose<real32>(const tmat3<real32> &m);
template tmat3<real64> transpose<real64>(const tmat3<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat4<T> transpose(const tmat4<T> &m)
{
	T	m00 = m.col[0].x;
	T	m10 = m.col[0].y;
	T	m20 = m.col[0].z;
	T	m30 = m.col[0].w;

	T	m01 = m.col[1].x;
	T	m11 = m.col[1].y;
	T	m21 = m.col[1].z;
	T	m31 = m.col[1].w;

	T	m02 = m.col[2].x;
	T	m12 = m.col[2].y;
	T	m22 = m.col[2].z;
	T	m32 = m.col[2].w;

	T	m03 = m.col[3].x;
	T	m13 = m.col[3].y;
	T	m23 = m.col[3].z;
	T	m33 = m.col[3].w;

	return tmat4<T>(m00, m01, m02, m03,
					m10, m11, m12, m13,
					m20, m21, m22, m23,
					m30, m31, m32, m33);
}

///////////////////////////////////////////////////////////////////////////////
template tmat4<real32> transpose<real32>(const tmat4<real32> &m);
template tmat4<real64> transpose<real64>(const tmat4<real64> &m);
///////////////////////////////////////////////////////////////////////////////

/// determinant
template<typename T>
T determinant(const tmat2<T> &m)
{
	T	m00 = m.col[0].x;
	T	m10 = m.col[0].y;

	T	m01 = m.col[1].x;
	T	m11 = m.col[1].y;

	T	res = m00 * m11 - m01 * m10;
	return res;
}

///////////////////////////////////////////////////////////////////////////////
template real32 determinant<real32>(const tmat2<real32> &m);
template real64 determinant<real64>(const tmat2<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
T determinant(const tmat3<T> &m)
{
	T	m00 = m.col[0].x;
	T	m10 = m.col[0].y;
	T	m20 = m.col[0].z;

	T	m01 = m.col[1].x;
	T	m11 = m.col[1].y;
	T	m21 = m.col[1].z;

	T	m02 = m.col[2].x;
	T	m12 = m.col[2].y;
	T	m22 = m.col[2].z;

	T	res = m00 * m11 * m22 + m01 * m12 * m20 + m02 * m10 * m21
			- m00 * m12 * m21 - m01 * m10 * m22 - m02 * m11 * m20;
	return res;

}

///////////////////////////////////////////////////////////////////////////////
template real32 determinant<real32>(const tmat3<real32> &m);
template real64 determinant<real64>(const tmat3<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
T determinant(const tmat4<T> &m)
{
	T	m00 = m.col[0].x;
	T	m10 = m.col[0].y;
	T	m20 = m.col[0].z;
	T	m30 = m.col[0].w;

	T	m01 = m.col[1].x;
	T	m11 = m.col[1].y;
	T	m21 = m.col[1].z;
	T	m31 = m.col[1].w;

	T	m02 = m.col[2].x;
	T	m12 = m.col[2].y;
	T	m22 = m.col[2].z;
	T	m32 = m.col[2].w;

	T	m03 = m.col[3].x;
	T	m13 = m.col[3].y;
	T	m23 = m.col[3].z;
	T	m33 = m.col[3].w;

	T	res = m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30
			- m03 * m11 * m22 * m30 + m01 * m13 * m22 * m30
			+ m02 * m11 * m23 * m30 - m01 * m12 * m23 * m30
			- m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31
			+ m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31
			- m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31
			+ m03 * m11 * m20 * m32 - m01 * m13 * m20 * m32
			- m03 * m10 * m21 * m32 + m00 * m13 * m21 * m32
			+ m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32
			- m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33
			+ m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33
			- m01 * m10 * m22 * m33 + m00 * m11 * m22 * m33;
	return res;
}

///////////////////////////////////////////////////////////////////////////////
template real32 determinant<real32>(const tmat4<real32> &m);
template real64 determinant<real64>(const tmat4<real64> &m);
///////////////////////////////////////////////////////////////////////////////

/// inverse
template<typename T>
tmat2<T> inverse(const tmat2<T> &m)
{
	T	m00 = m.col[0].x;
	T	m10 = m.col[0].y;

	T	m01 = m.col[1].x;
	T	m11 = m.col[1].y;

	T	inv_det = T(1) / (m00 * m11 - m01 * m10);

	T	r00 = m11 * inv_det;
	T	r01 = -m01 * inv_det;
	T	r10 = -m10 * inv_det;
	T	r11 = m00 * inv_det;

	return tmat2<T>(r00, r10, r01, r11);
}

///////////////////////////////////////////////////////////////////////////////
template tmat2<real32> inverse<real32>(const tmat2<real32> &m);
template tmat2<real64> inverse<real64>(const tmat2<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat3<T> inverse(const tmat3<T> &m)
{
	T	m00 = m.col[0].x;
	T	m10 = m.col[0].y;
	T	m20 = m.col[0].z;

	T	m01 = m.col[1].x;
	T	m11 = m.col[1].y;
	T	m21 = m.col[1].z;

	T	m02 = m.col[2].x;
	T	m12 = m.col[2].y;
	T	m22 = m.col[2].z;

	T	inv_det = T(1) / (m00 * m11 * m22 + m01 * m12 * m20 + m02 * m10 * m21
						  - m00 * m12 * m21 - m01 * m10 * m22 - m02 * m11 * m20);

	T	r00 = (m11 * m22 - m12 * m21) * inv_det;
	T	r01 = (m02 * m21 - m01 * m22) * inv_det;
	T	r02 = (m01 * m12 - m02 * m11) * inv_det;
	T	r10 = (m12 * m20 - m10 * m22) * inv_det;
	T	r11 = (m00 * m22 - m02 * m20) * inv_det;
	T	r12 = (m02 * m10 - m00 * m12) * inv_det;
	T	r20 = (m10 * m21 - m11 * m20) * inv_det;
	T	r21 = (m01 * m20 - m00 * m21) * inv_det;
	T	r22 = (m00 * m11 - m01 * m10) * inv_det;

	return tmat3<T>(r00, r10, r20, r01, r11, r21, r02, r12, r22);
}

///////////////////////////////////////////////////////////////////////////////
template tmat3<real32> inverse<real32>(const tmat3<real32> &m);
template tmat3<real64> inverse<real64>(const tmat3<real64> &m);
///////////////////////////////////////////////////////////////////////////////

template<typename T>
tmat4<T> inverse(const tmat4<T> &m)
{
	T	m00 = m.col[0].x;
	T	m10 = m.col[0].y;
	T	m20 = m.col[0].z;
	T	m30 = m.col[0].w;

	T	m01 = m.col[1].x;
	T	m11 = m.col[1].y;
	T	m21 = m.col[1].z;
	T	m31 = m.col[1].w;

	T	m02 = m.col[2].x;
	T	m12 = m.col[2].y;
	T	m22 = m.col[2].z;
	T	m32 = m.col[2].w;

	T	m03 = m.col[3].x;
	T	m13 = m.col[3].y;
	T	m23 = m.col[3].z;
	T	m33 = m.col[3].w;

	T	inv_det = T(1) / (m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30
						  - m03 * m11 * m22 * m30 + m01 * m13 * m22 * m30
						  + m02 * m11 * m23 * m30 - m01 * m12 * m23 * m30
						  - m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31
						  + m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31
						  - m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31
						  + m03 * m11 * m20 * m32 - m01 * m13 * m20 * m32
						  - m03 * m10 * m21 * m32 + m00 * m13 * m21 * m32
						  + m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32
						  - m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33
						  + m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33
						  - m01 * m10 * m22 * m33 + m00 * m11 * m22 * m33);

	T	r00 = (m12 * m23 * m31 - m13 * m22 * m31 + m13 * m21 * m32 - m11 * m23 * m32
			   - m12 * m21 * m33 + m11 * m22 * m33) * inv_det;
	T	r01 = (m03 * m22 * m31 - m02 * m23 * m31 - m03 * m21 * m32 + m01 * m23 * m32
			   + m02 * m21 * m33 - m01 * m22 * m33) * inv_det;
	T	r02 = (m02 * m13 * m31 - m03 * m12 * m31 + m03 * m11 * m32 - m01 * m13 * m32
			   - m02 * m11 * m33 + m01 * m12 * m33) * inv_det;
	T	r03 = (m03 * m12 * m21 - m02 * m13 * m21 - m03 * m11 * m22 + m01 * m13 * m22
			   + m02 * m11 * m23 - m01 * m12 * m23) * inv_det;
	T	r10 = (m13 * m22 * m30 - m12 * m23 * m30 - m13 * m20 * m32 + m10 * m23 * m32
			   + m12 * m20 * m33 - m10 * m22 * m33) * inv_det;
	T	r11 = (m02 * m23 * m30 - m03 * m22 * m30 + m03 * m20 * m32 - m00 * m23 * m32
			   - m02 * m20 * m33 + m00 * m22 * m33) * inv_det;
	T	r12 = (m03 * m12 * m30 - m02 * m13 * m30 - m03 * m10 * m32 + m00 * m13 * m32
			   + m02 * m10 * m33 - m00 * m12 * m33) * inv_det;
	T	r13 = (m02 * m13 * m20 - m03 * m12 * m20 + m03 * m10 * m22 - m00 * m13 * m22
			   - m02 * m10 * m23 + m00 * m12 * m23) * inv_det;
	T	r20 = (m11 * m23 * m30 - m13 * m21 * m30 + m13 * m20 * m31 - m10 * m23 * m31
			   - m11 * m20 * m33 + m10 * m21 * m33) * inv_det;
	T	r21 = (m03 * m21 * m30 - m01 * m23 * m30 - m03 * m20 * m31 + m00 * m23 * m31
			   + m01 * m20 * m33 - m00 * m21 * m33) * inv_det;
	T	r22 = (m01 * m13 * m30 - m03 * m11 * m30 + m03 * m10 * m31 - m00 * m13 * m31
			   - m01 * m10 * m33 + m00 * m11 * m33) * inv_det;
	T	r23 = (m03 * m11 * m20 - m01 * m13 * m20 - m03 * m10 * m21 + m00 * m13 * m21
			   + m01 * m10 * m23 - m00 * m11 * m23) * inv_det;
	T	r30 = (m12 * m21 * m30 - m11 * m22 * m30 - m12 * m20 * m31 + m10 * m22 * m31
			   + m11 * m20 * m32 - m10 * m21 * m32) * inv_det;
	T	r31 = (m01 * m22 * m30 - m02 * m21 * m30 + m02 * m20 * m31 - m00 * m22 * m31
			   - m01 * m20 * m32 + m00 * m21 * m32) * inv_det;
	T	r32 = (m02 * m11 * m30 - m01 * m12 * m30 - m02 * m10 * m31 + m00 * m12 * m31
			   + m01 * m10 * m32 - m00 * m11 * m32) * inv_det;
	T	r33 = (m01 * m12 * m20 - m02 * m11 * m20 + m02 * m10 * m21 - m00 * m12 * m21
			   - m01 * m10 * m22 + m00 * m11 * m22) * inv_det;

	return tmat4<T>(r00, r10, r20, r30,
					r01, r11, r21, r31,
					r02, r12, r22, r32,
					r03, r13, r23, r33);

}

///////////////////////////////////////////////////////////////////////////////
template tmat4<real32>	inverse<real32>(const tmat4<real32>& m);
template tmat4<real64>	inverse<real64>(const tmat4<real64>& m);
///////////////////////////////////////////////////////////////////////////////
} // namespace math
} // namespace raja
